fix(gate): the online gate has no key for the nvidia 27B, and a skipped model gate records as passed - #229
Merged
Merged
Conversation
localai-bot
force-pushed
the
row/GATE-SERVER-BINARY
branch
from
August 10, 2026 08:09
f7189aa to
0157a1e
Compare
localai-bot
pushed a commit
that referenced
this pull request
Aug 10, 2026
…, and make a model gate prove it ran Review of #229 (issue #222) returned CHANGES-REQUIRED. The examples/vllm-server repair and its CMake-parsing drift guard were confirmed correct; the 27n half was not. This resolves the findings. F1 -- the two shell-side 27n assertions had ZERO effective coverage. Each was a substring satisfied by the OTHER line: `${model} == 27n` occurs inside the --model guard, and `${model} == 27 || ${model} == 27n` occurs inside the test_name dispatch. Proven RED-free both ways on the shipped tests: reverting :243 to `27` only left 8/8 GREEN while 27n fell through to the else-arm (test_name=mxfp4_smoke_battery, gate_target=vllm-cli -- benched with no golden, verbatim what the docstring claims to prevent), and dropping 27n from the guard also left 8/8 GREEN. Both assertions now PARSE the driver: accepted_model_keys() reads the guard LINE and requires set equality with MODEL_REVISIONS, and correctness_gate_by_model_key() replays the if/elif/else chain and asserts the whole key->test_name mapping. Re-verified: mutation A now fails with 'test_qwen27_paged_engine' != 'mxfp4_smoke_battery', mutation B with "27n not found in frozenset({'q3mxfp4','27','35'})". F2 -- `if __name__ == "__main__"` sat BEFORE the second class, so `python3 tests/tools/test_online_gate_server_binary.py` ran 4 of 8 and printed OK. Moved to the end. The module's sibling convention imports tools.bench at module scope, so REPO_ROOT joins sys.path or the direct invocation would now die on ImportError instead of under-running. F3 -- the same defect was unfixed in a sibling driver, and the guard could not see it because it hardcoded two file paths. It now SCANS the live surfaces (scripts, tools, tests, examples, src, include, docs, cmake, release, docker, .github, README, root CMakeLists) for three shapes: a path component in front of examples/server, pathlib's "examples" / "server", and a BASENAME check against "server". That last shape found a site nobody had listed: PR #229 made online_gate.py record-execution write examples/vllm-server while gdn_packed_component.py:1559 still required `server.name != "server"` -- so the component driver rejected the manifest the shared harness had just written for it. Seven live sites fixed: dgx-gdn-packed-component.sh x3 (including the live server command array), gdn_packed_component.py, its fixture, run_serve_low.py's recipe manifest and docs/USAGE.md. NEEDS_DECISION -- README.md:168 and :368 are NOT fixed here and remain user- visible. scripts/check-doc-checkpoint.py refuses any README change whose commit does not also touch a landing source, and the file that decides the name the quick start tells a user to type -- examples/CMakeLists.txt OUTPUT_NAME -- is not on that list, while examples/{cli,server}/main.cpp are. This change has no honest reason to edit a listed file; manufacturing a cosmetic edit to one, or relaxing the checker, would both be weakening a gate to make a change pass. `4f24ff44` recorded this exact class ("a gate that rejects a true statement is not protecting anything") and repaired it by adding a REAL source to the list. The same decision is owed here. The scan therefore carries README in a one-file SCAN_BLOCKED_ON_POLICY set that names the blocker, guarded by a case asserting the set holds exactly that file AND that the debt still exists -- so the exclusion cannot outlive it or quietly grow. .agents/ and benchmarks/ are deliberately NOT scanned: they quote the command a past campaign actually ran, and rewriting them would falsify evidence rather than repair a consumer. scripts/dgx-online-serving.sh's `build_targets=(server)` is correct and untouched -- that is the CMake TARGET name. F4 -- the documented no-OUTPUT_NAME fallback was unsatisfiable: it demanded '"examples" / "server"' present AND absent. Removing the override and setting both harnesses to examples/server (correct for that world) yielded 2 red with the self-refuting message "still resolves the server as examples/server ...; the build emits examples/server". The stale-spelling assertion is now skipped when the target name IS the output name. F5 -- the 27n correctness precondition could pass VACUOUSLY and nothing recorded it. test_qwen27_paged_engine emits a MESSAGE and returns 0 when the UNSLOTH snapshot is absent; record_model_gate then wrote "passed": true unconditionally. A box with @0893e160 but not @890bdef7 -- the EXPECTED shape for a key whose whole point is a different checkpoint -- produced 27n.json marked passed with zero tokens compared. Now MODEL_GATE_CONTRACTS carries, per dispatched gate, the proof line it prints only after comparing tokens and the revision its committed goldens belong to. record_model_gate fails closed without the proof line and records golden_revision, model_revision and golden_covers_benched_checkpoint (deliberately false for 27n); the driver runs ctest -V so a PASSING run's output reaches the log at all; and the summary revalidates all of it. Two drift guards parse the markers out of the gates' own sources and the revision out of hf_snapshot.h, so a reworded MESSAGE fails here rather than silently disarming the check. F6 -- #222 added to the roadmap issue table, and the 27n key, its pinned revision, its build-sanity-only scope and its stop condition recorded in the EXISTING cuda-online-serving-gate spec. No new row. F7 -- the trace-only refusal said "defined only for the Qwen3.6-27B dense graph", which 27n IS. It now names the checkpoint whose graph contracts were captured. F8 noted, no action: 27n widens the cross-model summary default exactly as q3mxfp4 already does; not newly broken. Fixtures in test_online_gate_summary.py and test_online_gate_client.py are re-derived from the real gate log shape (they carried "passed\n"), not relaxed. GATES: 18 modules under tests/tools, 206 tests, GREEN (195 before; 11 new cases, every one shown red first). scripts/agent-preflight.sh exits 0. Refs #222, #213 FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: Claude:claude-opus-5 [ClaudeCode]
localai-bot
force-pushed
the
row/GATE-SERVER-BINARY
branch
from
August 10, 2026 13:43
0157a1e to
f09d16a
Compare
…ped model gate records as passed (#222) `main` already repaired the `examples/server` -> `examples/vllm-server` path (2b26262, 8fce04d), so this no longer carries that fix. What it carries is the three things that repair did not: **A model key for `nvidia/Qwen3.6-27B-NVFP4`.** The harness had keys for the unsloth 27B, the nvidia 35B and the MXFP4 8B, but none for the checkpoint the parity campaign targets and every recorded 0.85x number was taken on. Without a key that model can only be benched by an ad-hoc harness enforcing none of the pinned revision, oracle inventory, cache-drop or one-lock checks, so its numbers can never become accepted evidence. Key `27n` @0893e160 closes that -- it is the reproducible recipe #213's headline model otherwise has none of. `27` and `27n` are DIFFERENT models, not two spellings: different lm_head dtype, different mixed-precision layout, no shared goldens, non-comparable ratios. **A fail-closed model gate.** `tests/parity/test_qwen27_paged_engine.cpp` emits a loud MESSAGE and returns 0 when its snapshot is absent, so ctest exit 0 said nothing about whether a token was compared -- and `record-model-gate` wrote `"passed": true` regardless. On a box holding @0893e160 but not @890bdef7, the EXPECTED shape for `27n`, that produced a model gate marked passed with zero tokens compared. Now: `MODEL_GATE_CONTRACTS` pins each gate's proof line and the checkpoint its committed goldens belong to; `record-model-gate` refuses with "compared no token" unless the log carries that line; the driver runs `ctest -V` so a PASSING run's output actually reaches the log; and `golden_revision`, `model_revision` and `golden_covers_benched_checkpoint` (deliberately `false` for `27n` -- its precondition is build sanity on a neighbour's goldens) are written to the evidence and revalidated by the summary. A prose comment reaches neither the evidence nor a reader of the summary. **A drift guard**, `tests/tools/test_online_gate_server_binary.py`. It parses `examples/CMakeLists.txt` for `OUTPUT_NAME` rather than hardcoding a spelling, and SCANS the live surfaces for the stale path rather than naming the files it already knows about -- naming files is how #222's first repair missed the whole Python half and its second still left `docs/USAGE.md` and two README quick starts pointing at a binary the build has not produced since W6. `main`'s repair resolves the declared name and keeps `examples/server` as a REPLAY fallback, so a pre-W6 evidence tree still replays. The guard describes that reality instead of forcing this branch's hardcoded form: `FALLBACK_PATTERNS` admits the fallback SHAPE, and only in a file that resolves the declared name too -- a fallback whose primary is deleted is an ordinary hardcode and is reported again, and a fresh hardcode beside a primary is never laundered. `docs/USAGE.md`'s H3-over-HTTP quick start is repaired here. README.md is not: `check-doc-checkpoint.py` refuses any README change whose commit does not also touch a landing source, and `examples/CMakeLists.txt` -- the file that decides the name -- is not on that list. Recorded as one named file in `SCAN_BLOCKED_ON_POLICY`, with a test that the debt cannot grow or outlive itself, awaiting the same decision `4f24ff44` made for that class. Also fixes `test_trace_driver_builds_before_requiring_the_server_binary`, which 2b26262 left red on main: it anchored on `[[ -x ${build_dir}/examples/server ]]`, a line that repair replaced with the `server_bin` resolution. tests/tools: 208 pass (main: 187 with 1 error). 14 mutations of the claimed guarantees each turn the suite red. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: Claude:claude-opus-5 [ClaudeCode]
localai-bot
force-pushed
the
row/GATE-SERVER-BINARY
branch
from
August 10, 2026 13:49
f09d16a to
a7bb944
Compare
localai-bot
pushed a commit
that referenced
this pull request
Aug 10, 2026
…o four decimals First measurement of nvidia/Qwen3.6-27B-NVFP4 @0893e160 through a reproducible recipe. Every prior number for it came from an ad-hoc harness, because the canonical gate could not start a server (#222) and there was no model key for it until #229 added 27n. vllm.cpp 9ff2742e; oracle pip vLLM 0.25.0 + FlashInfer 0.6.13 in its PRODUCTION GRAPHED configuration, never --enforce-eager. Build guards confirmed present: FlashAttention-2 ENABLED for [121a], VLLM_CPP_TRITON resolved ON with real sm_121a AOT variants. Idle box, medians of 3, drop_caches between legs, noise band measured BEFORE any delta was read. c1 0.8289x, c2 0.8461x, c4 0.8529x, c8 0.8639x. This CONFIRMS the previously recorded 0.843-0.861x band, so the ad-hoc numbers were not wrong; they are kept as a superseded row rather than deleted. The step is now attributed. A decode-only nsys two-length diff with --cuda-graph-trace=node, BOTH arms in the same tool, node-level tracing proven by integral launch counts and two capture pairs agreeing to 0.005%: +8.6414 lm_head/Marlin +7.6068 fp8 tower +0.0532 splitK +1.0279 other = 17.3292 ms/step vs measured 17.3292 At 99.2/99.3% GPU-busy the c1 step is GPU-bound on both arms, so the whole gap is kernel time: no host, scheduler or launch-overhead lever exists here. Both levers are TRAFFIC/FUSION, not kernel quality. Our Marlin reaches 207.9 GiB/s against vLLM's 210.0 on the same combined shape, and both arms read identical fp8 bytes; we simply move more of them, and issue 96 GDN input GEMMs where vLLM issues 48 merged qkvz. Recorded honestly rather than flatteringly: RSS is 1.612x and BELOW FLOOR, c16/c32 are NOT MEASURED (one attempt lost the denominator to a foreign build contending mid-timing, the other to a host OOM-reboot), GPU memory is PENDING because the instrument returns N/A on this unified part, and our c1 ratio is host-memory-state sensitive in a way vLLM's is not (0.7604 vs 0.8289 across a reboot, protocols also differing, variables not separated). Startup is the one axis we win outright: 33.38 s vs 182.41 s, 5.46x faster. Written as table ROWS, not prose: the checker's budget is what forced that, and it was right that a scoreboard should stay a scoreboard. Refs #213, #252 FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: Claude:claude-opus-5 [ClaudeCode]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #222. The reproducible measurement path for #213.
What changed since review
This PR was reviewed MERGE at
0157a1e2and then stopped merging: two commitslanded on
mainwhile it was in review and did the same path repair.mainexamples/server→examples/vllm-serverpath repair2b262622,8fce04d3)27ntests/tools/test_online_gate_server_binary.py)The rename repair is gone from this branch.
main's version is keptverbatim — it is not re-landed, not reverted, and not reworded. The remaining
three contributions are what
main's repair did not do.1. A model key for
nvidia/Qwen3.6-27B-NVFP4(27n)The harness had keys for the unsloth 27B, the nvidia 35B and the MXFP4 8B, but
none for the checkpoint the parity campaign targets and every recorded 0.85x
number was taken on. Without a key, that model can only be benched by an ad-hoc
harness enforcing none of the pinned revision, oracle inventory, cache-drop or
one-lock checks, so its numbers can never become accepted evidence.
27n@
0893e160is wired throughMODEL_REVISIONS,MODEL_REPOSITORIES,MAX_NUM_BATCHED_TOKENS(2048, dense),MAX_MODEL_LEN, the shell--modelguard, the batched-token branch and the correctness-gate dispatch.
27and27nare different models, not two spellings: differentlm_headdtype, different mixed-precision layout, no shared goldens, non-comparable
ratios.
--trace-onlyrefuses27nand now says WHY — the node counts inTRACE_PRIMARY_GRAPH_CONTRACTSwere captured on @890bdef7alone, so therefusal is about which checkpoint, not which architecture.
2. A fail-closed model gate
tests/parity/test_qwen27_paged_engine.cppemits a loud MESSAGE and returns 0when its snapshot is absent, so
ctestexit 0 said nothing about whether atoken was compared — and
record-model-gatewrote"passed": trueregardless.On a box holding @
0893e160but not @890bdef7— the expected shape for27n— that producedpreflight/model-gate/27n.jsonmarked passed with zerotokens compared.
MODEL_GATE_CONTRACTSpins each dispatchable gate's proof line and thecheckpoint its committed goldens belong to.
record-model-gaterefuses with"compared no token"unless the log carriesthat line, and refuses a
test_namewith no contract at all.ctest -V, so a passing run's own output reaches the log(
--output-on-failureprints nothing for a pass).golden_revision,model_revisionandgolden_covers_benched_checkpoint(deliberately
falsefor27n, whose precondition is build sanity on aneighbour's goldens) are written to the evidence and revalidated by the
summary. A shell comment reaches neither the evidence nor a reader of the
summary.
The earlier review tried eight ways to make this pass vacuously and failed each
time; that property was re-verified after the rebase (see Verification).
3. The drift guard, adapted to
main's formtests/tools/test_online_gate_server_binary.pyparsesexamples/CMakeLists.txtfor
OUTPUT_NAMErather than hardcoding a spelling, and SCANS the live surfacesfor the stale path rather than naming files it already knows about — naming
files is how #222's first repair missed the whole Python half, and how its
second still left three live sites.
mainfixed the paths differently, and the guard now describes that realityrather than forcing this branch's form.
maindoes not hardcode the new name:it resolves
examples/<OUTPUT_NAME>and keepsexamples/serveras a REPLAYFALLBACK so a pre-W6 evidence tree still replays against the binary it was
recorded with. The guard's original line-level rejection would have failed
against that. It now admits the fallback by shape (
FALLBACK_PATTERNS), andonly in a file that resolves the declared name too — so:
mentions the new name" can never launder an occurrence;
gdn_packed_component.py'sserver.name not in ("vllm-server", "server")needs no exemption — it admits both names, so it never matches at all, while a
regression to
!= "server"still does.Two cases were added for this: one proving those three properties, and one
proving the fallback is actually present in all three drivers, so silently
dropping pre-W6 replay cannot go unnoticed.
docs/USAGE.md's H3-over-HTTP quick start is repaired here.README.mdis not:check-doc-checkpoint.pyrefuses any README change whose commit does not alsotouch a landing source, and
examples/CMakeLists.txt— the file that decidesthe name — is not on that list. Recorded as one named file in
SCAN_BLOCKED_ON_POLICY, with a test that the debt can neither grow nor outliveitself, awaiting the decision
4f24ff44made for this exact class.Incidental:
mainis currently red2b262622lefttest_trace_driver_builds_before_requiring_the_server_binaryfailing on
main— it anchors on[[ -x ${build_dir}/examples/server ]], theline that repair replaced with the
server_binresolution. Re-anchored here onthe resolution line, which is what the ordering assertion is actually about.
The self-inflicted regression this PR originally caught —
record-executionwriting
examples/vllm-serverwhilegdn_packed_component.py:1559requiredbasename
server— was re-checked againstmain's version and does notrecur:
8fce04d3widened that check to accept both names.Verification (all CPU/Python)
python3 -m unittest discover -s tests/tools -t .onmainscripts/agent-preflight.sh/--stagedscripts/check-pr-size.py --base origin/mainscripts/check-doc-checkpoint.py208 = 187 + 19 (the guard's 18 cases + 1 summary case) + 2 (the two new
fallback cases) — with
main's one error fixed.Mutation battery. 14 mutations of the claimed guarantees, each applied to a
scratch copy of this head: the shell fallback reduced to a plain hardcode; the
Python primary deleted; the gdn basename check regressed to
!= "server";-Vremoved;
27ndropped fromMODEL_REVISIONS;27ndropped from the shellguard; the proof-line check neutered;
docs/USAGE.mdre-staled;27nfallingthrough to the no-golden else-arm;
golden_covers_benched_checkpointhardcodedTrue; the summary's scope revalidation removed; the trace-only refusal losingthe checkpoint name; a proof marker reworded;
SCAN_BLOCKED_ON_POLICYwidenedto a second file. All 14 turn the suite red; the restored tree is green.
Conflict resolution, per file:
tools/bench/online_gate.pymain'sserver_binary()helper and its 3 call sites kept verbatim;27n+MODEL_GATE_CONTRACTS+record_model_gatereapplied on topscripts/dgx-online-serving.shmain'sserver_binresolution kept verbatim; the five27n/ctest -Vedits reapplied on toptools/bench/gdn_packed_component.pymain's version taken wholesale; this branch's change droppedscripts/dgx-gdn-packed-component.shmain's version taken wholesale; this branch's change droppedtools/bench/run_serve_low.pymainalready has it; dropped.agents/roadmap_v1.mdmain's version taken wholesale, the#222row reapplied (no#213row present to collide with)docs/USAGE.mdmain's version taken wholesale, the one quick-start line reapplied🤖 Generated with Claude Code